//
//  Network+Download.m
//  YanXiuWang
//
//  Created by 慧趣小歪 on 16/12/15.
//  Copyright © 2016年 小分队. All rights reserved.
//

#import "Network+Download.h"
#import <CommonCrypto/CommonDigest.h>
#import "NSString+Format.h"
@interface ResponseDownload () {
    @package
    __weak __kindof NSURLSessionTask *_task;
    NSProgress *_progress;
    int _stateCode;
}

@end

@implementation NetworkManager (Download)

+ (NSString *)filePathByBookmarkPath:(NSString *)bookmarkFile {
    // 文件管理
    NSFileManager * fileManager = [NSFileManager defaultManager];
    
    // 如果 未下载过 则直接开始下载
    BOOL isDictionary = NO;
    if (![fileManager fileExistsAtPath:bookmarkFile isDirectory:&isDictionary] || isDictionary) {
        return nil;
    }
    
    NSData *data = [NSData dataWithContentsOfFile:bookmarkFile];
    
    // 如果 下载文件标签0字节 则直接开始下载
    if (data.length == 0)return nil;
    
    NSError *error = nil;
    BOOL isStale = NO;
    NSURL *fileURL = [[NSURL alloc] initByResolvingBookmarkData:data options:NSURLBookmarkResolutionWithoutMounting relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
    
    // 如果 下载文件标签无效 则直接开始下载
    if (fileURL == nil || error != nil)return nil;
    
    // 如果书签数据不存在或者已删除 则 删除书签 并 重新下载
    NSString *filePath = fileURL.relativePath;
    if (![fileManager fileExistsAtPath:filePath isDirectory:&isDictionary] || isDictionary) {
        return nil;
    }
    return filePath;
}

+ (NSUInteger)fileSizeByBookmarkPath:(NSString *)bookmarkFile {
    
    NSString *filePath = [NetworkManager filePathByBookmarkPath:bookmarkFile];
    
    if (filePath == nil) return 0;
    
    NSError *error;
    NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error];
    if (attr == nil || error != nil) {
        return 0;
    }
    
    NSNumber *fileSize = @([attr[NSFileSize] longLongValue]);
    return fileSize.unsignedIntegerValue;
}

- (NSUInteger)diskCacheSize {
    NSUInteger totalSize = 0;
    NSString *downloadRoot = [NetworkManager makeDiskCachePath:@"com.jlhhjy.downloads"];
    NSString *bookmarkRoot = [downloadRoot stringByAppendingPathComponent:@"bookmarks"];
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    NSError *error;
    NSArray<NSString *> *subFiles = [fileManager contentsOfDirectoryAtPath:bookmarkRoot error:&error];
    for (NSString *subFile in subFiles) {
        NSString *path = [bookmarkRoot stringByAppendingPathComponent:subFile];
        NSString *mark = [path stringByAppendingPathComponent:@"download.mark"];
        
        totalSize += [NetworkManager fileSizeByBookmarkPath:mark];
    }
    return totalSize;
}

- (NSUInteger)fileSizeByURL:(NSString *)url {
    return [NetworkManager fileSizeByBookmarkPath:[NetworkManager bookmarkFileForKey:url]];
}

- (void)clearDisk {
    NSString *downloadRoot = [NetworkManager makeDiskCachePath:@"com.jlhhjy.downloads"];
    NSString *bookmarkRoot = [downloadRoot stringByAppendingPathComponent:@"bookmarks"];
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    NSError *error;
    NSArray<NSString *> *subFiles = [fileManager contentsOfDirectoryAtPath:bookmarkRoot error:&error];
    for (NSString *subFile in subFiles) {
        NSString *path = [bookmarkRoot stringByAppendingPathComponent:subFile];
        NSString *data = [bookmarkRoot stringByAppendingPathComponent:@"download.data"];
        NSString *mark = [path stringByAppendingPathComponent:@"download.mark"];
        NSString *file = [NetworkManager filePathByBookmarkPath:mark];
        
        // 删除已下载的文件 和书签
        [fileManager removeItemAtPath:file error:&error];
        [fileManager removeItemAtPath:mark error:&error];
        [fileManager removeItemAtPath:data error:&error];
        [fileManager removeItemAtPath:path error:&error];
    }
}

+ (NSString *)bookmarkFileForKey:(NSString *)key {
    return [[NetworkManager bookmarkPathForKey:key]
            stringByAppendingPathComponent:@"download.mark"];
}

+ (NSString *)bookmarkPathForKey:(NSString *)key {
    NSString *fileName = [NetworkManager cachedFileNameForKey:key];
    // 下载根目录
    NSString *downloadRoot = [NetworkManager makeDiskCachePath:@"com.jlhhjy.downloads"];
    NSString *bookmarkRoot = [downloadRoot stringByAppendingPathComponent:@"bookmarks"];
    return [bookmarkRoot stringByAppendingPathComponent:fileName];
}

+ (NSString *)cachedFileNameForKey:(NSString *)key {
    const char *str = [key UTF8String];
    if (str == NULL) {
        str = "";
    }
    unsigned char r[CC_MD5_DIGEST_LENGTH];
    CC_MD5(str, (CC_LONG)strlen(str), r);
    
    NSString *filename =
    [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
     r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]];
    
    return filename;
}
// Init the disk cache
+ (NSString *)makeDiskCachePath:(NSString*)fullNamespace {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    return [paths[0] stringByAppendingPathComponent:fullNamespace];
}

// 默认下载响应队列
- (NetworkDownloadQueue *)downloadQueue {
    static NetworkDownloadQueue *queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        queue = [NetworkDownloadQueue new];
        [queue setValue:[NSMutableArray arrayWithCapacity:1] forKey:@"requests"];
    });
    return queue;
}

// 下载文件
- (NET_DOWN_URL)download {
    return self.downloadQueue.download;
}

@end

#pragma mark - Download Delegate
@implementation NetworkDownloadQueue

// 无论成功失败都会走这里 用来做完成回调
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    ResponseDownload *response = task.netResponse;
    RequestDownload *request = response.request;
    NetworkDownloadQueue *queue = request.queue;
    
    [queue.requests removeObject:task];
    
    if (error != nil && error.code != -999) {
        NSMutableDictionary *source = response.source.mutableCopy;
        source[@"error"] = error;
        response.source = source;
        
        print(@"error:%ld  message:%@", (long)error.code, [error localizedDescription]);
    }
    
    // 调用下载完成事件
    OnDownloadFinish onFinish = response.source[@"onFinish"];
    onFinish(response);
}

/// 下载完成
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location {
    
    ResponseDownload *response = downloadTask.netResponse;
    RequestDownload *request = response.request;
    
    NSString *key = [request valueForKey:@"URL"];
    
    NSString *bookmarkPath = [NetworkManager bookmarkPathForKey:key];
    NSString *bookmarkFile = [bookmarkPath stringByAppendingPathComponent:@"download.mark"];
    NSURL *downloadURL = response.source[@"localURL"]; //[bookmarkPath stringByAppendingPathComponent:@"download.file"];
    
    // 删除缓存数据
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    NSString *parentPath = [downloadURL URLByDeletingLastPathComponent].relativePath;
    BOOL isDictionary = NO;
    if (![fileManager fileExistsAtPath:parentPath isDirectory:&isDictionary] || !isDictionary) {
        [fileManager createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:nil];
    }
    
    // 删除旧的 已下载文件或书签 如果有的话.
    [fileManager removeItemAtPath:bookmarkFile error:nil];
    [fileManager removeItemAtURL:downloadURL error:nil];
    
    // 将新下载完成的文件移动到 文件路径
    [fileManager moveItemAtURL:location toURL:downloadURL error:nil];
    //[fileManager moveItemAtURL:location toURL:fileURL error:nil];
    
    // 保存书签数据, 已方便以后完成
    NSData *data = [downloadURL bookmarkDataWithOptions:NSURLBookmarkCreationMinimalBookmark includingResourceValuesForKeys:nil relativeToURL:nil error:nil];
    [data writeToFile:bookmarkFile options:NSDataWritingWithoutOverwriting error:nil];
    
    response.location = downloadURL;
}

/// 下载进度变化
/* Sent periodically to notify the delegate of download progress. */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
    
    ResponseDownload *response = downloadTask.netResponse;
    
    response.localSize = totalBytesWritten;
    response.totalSize = totalBytesExpectedToWrite;
    
    NET_PROGRESS_BLOCK onProgress = response.source[@"onProgress"];
    onProgress(response.progress);
    //print(@"->已下载 %.2f%%", response.progressPercent * 100);
}

/* Sent when a download has been resumed. If a download failed with an
 * error, the -userInfo dictionary of the error will contain an
 * NSURLSessionDownloadTaskResumeData key, whose value is the resume
 * data.
 */
// 断点续传接着下载
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes {
    
    ResponseDownload *response = downloadTask.netResponse;
    
    response->_stateCode = 200;
    
    response.localSize = fileOffset;
    response.totalSize = expectedTotalBytes;
    
    NET_PROGRESS_BLOCK onProgress = response.source[@"onProgress"];
    onProgress(response.progress);
    //print(@"=>已下载 %.2f%%", response.progressPercent * 100);
}

// 下载请求转下载
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask {
    ResponseDownload *response = dataTask.netResponse;
    RequestDownload *request = response.request;
    NetworkDownloadQueue *queue = request.queue;
    downloadTask.netResponse = response;
    response->_task = downloadTask;
    [queue.requests addObject:downloadTask];
}

- (void)testNetStateWithSize:(long long)fileSize
           completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
    // 如果是移动蜂窝网络, 则提示用户会消耗流量
    if (self.hostReachability.currentReachabilityStatus == ReachableViaWWAN) {
        
        NSString *message = [NSString stringWithFormat:@"您正在使用移动蜂窝网络，下载将消耗 %.2fM 数据流量%@", (double)fileSize / (1024.0 * 1024.0), fileSize >= 1024 * 1024 ? @"，建议您使用WiFi环境下载！" : @""];
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"流量提醒" message: message preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"取消下载" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(NSURLSessionResponseCancel);
        }]];
        [alert addAction:[UIAlertAction actionWithTitle:@"继续下载" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(NSURLSessionResponseBecomeDownload);
        }]];
        [[UIApplication sharedApplication].windows.firstObject.rootViewController presentViewController:alert animated:YES completion:nil];
        return;
    }
    // 否则直接开始下载
    completionHandler(NSURLSessionResponseBecomeDownload);
}

/// 下载响应服务端返回结果, 判断文件是否需要重下.
- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
//    NSStringEncoding convertEncoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingWindowsLatin1);
//    NSStringEncoding convertEncoding2 = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF8);
//
//    NSData *data1 = [response.suggestedFilename dataUsingEncoding:convertEncoding2 allowLossyConversion:YES];
//    
//    NSString *realFileName = [NSString stringWithData:data1 encoding:convertEncoding];
//    print(@"%@", realFileName);
    
    ResponseDownload *netResponse = dataTask.netResponse;
    OnDownloadFinish onFinish = netResponse.source[@"onFinish"];
    
    // 如果不是HTTP响应 则取消这次请求
    if (![response isKindOfClass:NSHTTPURLResponse.class]) {
        NSString *message = Format(@"未知的下载请求响应:%@", NSStringFromClass(response.class));
        print(@" --> %@", message);
        completionHandler(NSURLSessionResponseCancel);
        NSMutableDictionary *source = (NSMutableDictionary *) netResponse.source;
        source[@"error"] = [NSError errorWithDomain:message code:-3001 userInfo:nil];
        onFinish(netResponse);
        return [dataTask cancel];
    }
    
    // 源数据
    NSMutableDictionary *source = (NSMutableDictionary *) netResponse.source;
    
    // 206 是断点续传
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    NSInteger statusCode = httpResponse.statusCode;
    
    // 获取更新服务器时间与本地时间差
    NSString *dateString = httpResponse.allHeaderFields[@"Date"] ?: @"Thu, 01 Jan 1970 00:00:00 GMT";
    NSDateFormatter *formatter = [NSDateFormatter new];
    formatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
    formatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss Z";
    
    NSDate *date = [formatter dateFromString:dateString] ?: [NSDate dateWithTimeIntervalSince1970:0];
    [NetworkManager shared].timeOffset = date.timeIntervalSince1970 - [NSDate date].timeIntervalSince1970;
    source[@"date"] = date;
    
    netResponse->_stateCode = (int)statusCode;
    
    if (statusCode != 200 && statusCode != 206) {
        NSString *message = Format(@"非下载网络状态:%@", NSStringFromClass(response.class));
        print(@" --> %@", message);
        completionHandler(NSURLSessionResponseCancel);
        source[@"error"] = [NSError errorWithDomain:message code:-3002 userInfo:nil];
//        onFinish(netResponse);
        return [dataTask cancel];
    }
    
    // 如果未强制下载路径， 则优先使用 服务器返回的文件名
    NSURL *localURL = netResponse.request.blockMap[@"localURL"];
    if (localURL == nil) {
//        NSString *disposition = httpResponse.allHeaderFields[@"Content-Disposition"];
//        
//        NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:@"\\bfilename=\"([^\"]*?)\"" options:NSRegularExpressionCaseInsensitive error:nil];
//        
//        NSTextCheckingResult *match = [regular firstMatchInString:disposition options:0 range:NSMakeRange(0, disposition.length)];
//        
//        NSString *fileName = response.URL.lastPathComponent;
//        if (disposition.length > 0 && match.range.location != NSNotFound) {
//            fileName = [disposition substringWithRange:[match rangeAtIndex:1]];
//            
//            NSData *data = [fileName dataUsingEncoding:NSUnicodeStringEncoding];
//            fileName = [NSString stringWithData:data encoding:-2147483125];
//        }
        NSString *fileName = response.suggestedFilename;
        NSString *key = [netResponse.request valueForKey:@"URL"];
        NSString *bookmarkPath = [NetworkManager bookmarkPathForKey:key];
        source[@"localURL"] = [[NSURL fileURLWithPath:bookmarkPath] URLByAppendingPathComponent:fileName]; //[bookmarkPath stringByAppendingPathComponent:fileName];
    }
    print(@"Content-Disposition:%@",source[@"localURL"]);
    // 获得需下载的内容大小
    long long totalSize = [httpResponse.allHeaderFields[@"Content-Length"] longLongValue];
    
    // 如果是断点续传, 直接开始下载
    if (statusCode != 200) return [self testNetStateWithSize:totalSize completionHandler:completionHandler]; //completionHandler(NSURLSessionResponseBecomeDownload);
    
    RequestDownload *request = dataTask.netResponse.request;
    
    NSString *key = [request valueForKey:@"URL"];
    
    NSString *bookmarkFile = [NetworkManager bookmarkFileForKey:key];
    
    // 文件管理
    NSFileManager * fileManager = [NSFileManager defaultManager];
    
    // 如果 未下载过 则直接开始下载
    BOOL isDictionary = NO;
    if (![fileManager fileExistsAtPath:bookmarkFile isDirectory:&isDictionary] || isDictionary) {
       return [self testNetStateWithSize:totalSize completionHandler:completionHandler];
    }
    
    NSData *data = [NSData dataWithContentsOfFile:bookmarkFile];
    
    // 如果 下载文件标签0字节 则直接开始下载
    if (data.length == 0)return [self testNetStateWithSize:totalSize completionHandler:completionHandler];
    
    NSError *error = nil;
    BOOL isStale = NO;
    NSURL *fileURL = [[NSURL alloc] initByResolvingBookmarkData:data options:NSURLBookmarkResolutionWithoutMounting relativeToURL:nil bookmarkDataIsStale:&isStale error:&error];
    
    // 如果 下载文件标签无效 则直接开始下载
    if (fileURL == nil || error != nil)return [self testNetStateWithSize:totalSize completionHandler:completionHandler];
    
    // 如果书签数据不存在或者已删除 则 删除书签 并 重新下载
    NSString *filePath = fileURL.relativePath;
    if (![fileManager fileExistsAtPath:filePath isDirectory:&isDictionary] || isDictionary) {
        [fileManager removeItemAtPath:bookmarkFile error:&error];
       return [self testNetStateWithSize:totalSize completionHandler:completionHandler];
    }
    
    // 与文件大小比较
    long long localSize = 0;
    NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error];
    if (attr != nil && error == nil) {
        localSize = [attr[NSFileSize] longLongValue];
    }
    
    // 已下载的文件和最新文件大小不一致 重新下载
    if (totalSize != localSize)return [self testNetStateWithSize:totalSize completionHandler:completionHandler];
    
    netResponse.localSize = localSize;
    netResponse.totalSize = totalSize;
    netResponse.location = fileURL;
    
    // 如果要下载的文件 和 已下载的文件一致 则取消下载 返回成功
    completionHandler(NSURLSessionResponseCancel);
    [dataTask cancel];
}

- (void)applicationWillTerminate:(NSNotification *)notification {
    
    for (NSURLSessionTask *task in self.requests) {
        if ([task isKindOfClass:[NSURLSessionDownloadTask class]]) {
            [((NSURLSessionDownloadTask *)task)
             cancelByProducingResumeData:^(NSData * resumeData) {
                NSString *path = task.netResponse.source[@"dataPath"];
                [resumeData writeToFile:path atomically:NO];
            }];
        } else {
            [task cancel];
        }
    }
}

- (NSURLSession *)downloadSession {
    static NSURLSession *session;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
        //[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: [NSBundle mainBundle].bundleIdentifier ?: @"com.jlhhjy.download"];
        config.timeoutIntervalForRequest = 30;
        config.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
        
        session = [NSURLSession sessionWithConfiguration:config
                                                delegate:self
                                           delegateQueue:[NSOperationQueue new]];
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];
    });
    
    return session;
}

- (NET_DOWN_URL)download {
    return ^(NSString *url) {
        RequestDownload *task = [RequestDownload new];
        [task setValue:url forKey:@"URL"];
        [task setValue:self forKey:@"queue"];
        return task;
    };
}

@end

@implementation ResponseDownload

- (int)stateCode {
    return _stateCode;
}

- (NSData *)data {
    if (_location == nil) return nil;
    return [NSData dataWithContentsOfURL:_location options:NSDataReadingUncached error:nil];
}

- (NSProgress *)progress {
    if (_progress == nil) {
        _progress = [NSProgress progressWithTotalUnitCount:_totalSize];
    }
    _progress.completedUnitCount = _localSize;
    return _progress;
}

- (void)cancel {
    
    if ([_task isKindOfClass:NSURLSessionDownloadTask.class]) {
        NSURLSessionDownloadTask *task = _task;
        [task cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
            NSString *path = task.netResponse.source[@"dataPath"];
            [resumeData writeToFile:path options:NSDataWritingWithoutOverwriting error:nil];
        }];
        return;
    }
    [_task cancel];
}

- (double)progressPercent {
    return self.progress.progressPercent;
}

@end

@implementation RequestDownload

- (NET_DWON_TEXT)to {
    return ^(NSString *localPath) {
        self.blockMap[@"localPath"] = localPath;
        return self;
    };
}

- (NET_DOWN_PROGRESS)progress {
    return ^(NET_PROGRESS_BLOCK _Nonnull progressBlock) {
        self.blockMap[@"onProgress"] = [progressBlock copy];
        return self;
    };
}

- (nonnull ResponseDownload *)onFinish:(OnDownloadFinish _Nonnull)onFinishBlock {
    //__block OnDownloadFinish onFinish = [onFinishBlock copy];
    NetworkDownloadQueue *queue = self.queue;
    ResponseDownload *downloadResponse = [ResponseDownload new];
    NSURLSessionTask *task;
    NSMutableDictionary *source = [NSMutableDictionary dictionary];
    
    // 根据网址 创建 文件 MD5 名
    NSString *key = [self valueForKey:@"URL"];
    
    // 下载根目录
    NSString *bookmarkPath = [NetworkManager bookmarkPathForKey:key];
    
    // 文件管理
    NSFileManager * fileManager = [NSFileManager defaultManager];
    
    // 如果 文件不存在 或不是目录 则创建
    BOOL isDictionary = NO;
    if (![fileManager fileExistsAtPath:bookmarkPath isDirectory:&isDictionary] || !isDictionary) {
        [fileManager createDirectoryAtPath:bookmarkPath withIntermediateDirectories:YES attributes:nil error:nil];
    }
    
    NSURLSession *session = [NetworkManager shared].downloadQueue.downloadSession;
    
    __block OnDownloadFinish onFinish = [onFinishBlock copy];
    __block NET_PROGRESS_BLOCK onProgress = self.blockMap[@"onProgress"];

    // 如果有未下载完成的数据
    NSString *cacheDataPath = [bookmarkPath stringByAppendingPathComponent:@"download.data"];
    
    NSData *params = [self valueForKey:@"POSTParams"];
    
    NSString *fileName = [NSURL URLWithString:key].lastPathComponent ?: key.lastPathComponent;
    
    NSURL *bookmarkURL = [NSURL fileURLWithPath:bookmarkPath];

    if (self.blockMap[@"localPath"] == nil) {
        source[@"localURL"] = [bookmarkURL URLByAppendingPathComponent:fileName];
    } else {
        source[@"localURL"] = [NSURL fileURLWithPath:self.blockMap[@"localPath"]];
    }
    
    source[@"params"] = [[NSString alloc] initWithData:params encoding:NSUTF8StringEncoding];
    source[@"dataPath"] = cacheDataPath;
    source[@"request"] = self;
    source[@"onFinish"] = ^(ResponseDownload *response) {
        if (onFinish == nil) return;
        
        if ([NSThread isMainThread]) return onFinish(response);
        
        dispatch_async(dispatch_get_main_queue(), ^{
            onFinish(response);
        });
    };
    
    source[@"onProgress"] = ^(NSProgress *progress) {
        if (onProgress == nil) return;
        
        if ([NSThread isMainThread]) return onProgress(progress);
        
        dispatch_async(dispatch_get_main_queue(), ^{
            onProgress(progress);
        });
    };
    
    NSError *error;
    
    // 如果存在未下载完成的缓存 则从缓存断点续传
    if ([fileManager fileExistsAtPath:cacheDataPath isDirectory:&isDictionary] && !isDictionary) {
        
        // 从上次未完成的缓存开始下载
        NSData *data = [NSData dataWithContentsOfFile:cacheDataPath];
        
        [fileManager removeItemAtPath:cacheDataPath error:&error];
        
        task = [session downloadTaskWithResumeData:data];
        
        [queue.requests addObject:task];
    } else {
        
        // 开始全新的下载
        NSURLRequest *request = [[NetworkManager getURLRequestWithTask:self] copy];
        
        source[@"urlRequest"] = request;
        
        task = [session dataTaskWithRequest:request];
    }
    
    downloadResponse->_task = task;
    downloadResponse.source = source;
    task.netResponse = downloadResponse;
    
    [task resume];
    return downloadResponse;
}


@end
